﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//  OperationalLogs.cs
//    
// Abstract:
//
//  This module implements the OperationalLogs class. This is a static class that defines all the methods for writing 
//  operational log messages.
//  
//--

using System;
using System.Diagnostics;

using Microsoft.OfficeCommunicationsServer.Applications.Common;

namespace Microsoft.EnhancedReminders
{
    /// <summary>
    /// Static methods for writing operational log messages.
    /// </summary>
    public static class OperationalLogs
    {
        /// <summary>
        /// Logs an error message to the event log that there was a problem accessing the specified message queue.
        /// </summary>
        /// <param name="queueName">The name of the message queue associated with the error</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when there is any kind of error accessing a message queue (that isn't fatal). The most likely
        /// cause of this error is that the queue doesn't exist or has the wrong permissions. The consequence of this type of error
        /// is that users won't receive notifications.
        /// </remarks>
        public static void LogMessageQueueError(string queueName, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(queueName), "!String.IsNullOrEmpty(queueName)");

            if (ex != null)
            {
                Logger.WriteOperationalError(0x01 /* eventId*/, ex, LogStrings.MessageQueueError, queueName);
            }
            else
            {
                // There might not be an excpetion associated with this error. For example, MessageQueue.CanWrite might have been 
                // checked prioer to accessing the queue.
                Logger.WriteOperationalError(0x01, LogStrings.MessageQueueError, queueName);
            }
        }

        /// <summary>
        /// Logs an error message to the event log that there was a problem accessing the specified message queue that caused the service to stop.
        /// </summary>
        /// <param name="queueName">The name of the message queue associated with the error</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when there is any kind of error accessing a message queue that stops the affected service from 
        /// running. The most likely cause of this error is that the queue doesn't exist or has the wrong permissions. The 
        /// consequence of this type of error is that the service won't run and users won't receive notifications.
        /// </remarks>
        public static void LogMessageQueueFatalError(string queueName, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(queueName), "!String.IsNullOrEmpty(queueName)");
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x02 /* eventId*/, ex, LogStrings.MessageQueueFatalError, queueName);
        }

        /// <summary>
        /// Logs an error message to the event log that the CAS server could not be found for the specified user.
        /// </summary>
        /// <param name="user">The user account experiencing the error</param>
        /// <remarks>
        /// This method is invoked when the Client Access Server (CAS) cannot be found for a given user. This is most likely caused by
        /// an external issue such as the CAS machines being unreachable or not operating correctly. The consequence of this error is that
        /// the affected user won't receive any notifications.
        /// </remarks>
        public static void LogFindingCasError(string user)
        {
            Debug.Assert(!String.IsNullOrEmpty(user), "!String.IsNullOrEmpty(user)");

            Logger.WriteOperationalError(0x03 /* eventId*/, LogStrings.FindingCasError, user);
        }

        /// <summary>
        /// Logs an error message to the event log that the mailbox of the specified user could not be accessed.
        /// </summary>
        /// <param name="user">The user account experiencing the error</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when there are any failures creating or accessing the search folders used by the server for a given 
        /// user. This is most likely caused by an external error such as the CAS machines being unreachable or Exchange not operating 
        /// correctly. It could also be caused by the service having insufficient privileges to access the mailbox. The consequence 
        /// of this error is that the affected user won't receive any notifications.
        /// </remarks>
        public static void LogMailboxAccessError(string user, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(user), "!String.IsNullOrEmpty(user)");
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x04 /* eventId*/, ex, LogStrings.MailboxAccessError, user);
        }

        /// <summary>
        /// Logs an error message to the event log that a mailbox item for the specified user could not be accessed.
        /// </summary>
        /// <param name="user">The user account experiencing the error</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when there are any failures accessing individual mailbox items for a given user. This is most likely 
        /// caused by an external error such as the CAS machines being unreachable or Exchange not operating correctly. It could also be 
        /// caused by the service having insufficient privileges to access the mailbox. The consequence of this error is that the 
        /// affected user won't receive any notifications.
        /// </remarks>
        public static void LogMailboxItemAccessError(string user, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(user), "!String.IsNullOrEmpty(user)");
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x05 /* eventId*/, ex, LogStrings.MailboxItemAccessError, user);
        }

        /// <summary>
        /// Logs an error message to the event log that the specified configuration setting is not set.
        /// </summary>
        /// <param name="settingName">Name of the missing setting</param>
        /// <remarks>
        /// This method is invoked when a required configuration setting is not set. The consequence of this type of error is that 
        /// the service won't start and users won't receive notifications.
        /// </remarks>
        public static void LogMissingSettingError(string settingName)
        {
            Debug.Assert(!String.IsNullOrEmpty(settingName), "!String.IsNullOrEmpty(settingName)");

            Logger.WriteOperationalError(0x06 /* eventId*/, LogStrings.MissingSettingError, settingName);
        }

        /// <summary>
        /// Logs an error message to the event log that the value of the specified configuration setting is invalid.
        /// </summary>
        /// <param name="settingName">Name of the invalid setting</param>
        /// <remarks>
        /// This method is invoked when the value of a required configuration setting is invalid. The consequence of this type of error 
        /// is that the service won't start and users won't receive notifications.
        /// </remarks>
        public static void LogInvalidSettingError(string settingName)
        {
            Debug.Assert(!String.IsNullOrEmpty(settingName), "!String.IsNullOrEmpty(settingName)");

            Logger.WriteOperationalError(0x07 /* eventId*/, LogStrings.InvalidSettingError, settingName);
        }

        /// <summary>
        /// Logs a warning message to the event log that the service was unable to find any users.
        /// </summary>
        /// <remarks>
        /// This method is invoked when the service starts with no users. This might be expected, or might be the result of incorrect 
        /// configuration settings or an external issue with Active Directory. The consequence of this warning is that no users will 
        /// receive notifications.
        /// </remarks>
        public static void LogNoUsersWarning()
        {
            Logger.WriteOperationalWarning(0x08 /* eventId*/, LogStrings.NoUsersWarning, Constants.MembershipDLSetting, Constants.ActiveDirectoryRootSetting);
        }

        /// <summary>
        /// Logs an error message to the event log that the service was unable to access any of the users' mailboxes successfully.
        /// </summary>
        /// <remarks>
        /// This method is invoked when none of the mailboxes for the configured users can be accessed. This is mostly because of an 
        /// external issue with Exchange or because the service doesn't have sufficient privileges. The consequence of this error is 
        /// that no users will receive notfications.
        /// </remarks>
        public static void LogNoUsersError()
        {
            Logger.WriteOperationalError(0x09 /* eventId*/, LogStrings.NoUsersError);
        }

        /// <summary>
        /// Log an informational message to the event log that the service is starting.
        /// </summary>
        /// <remarks>
        /// This method is invoked when one of the Enhanced Reminders services begins to start.
        /// </remarks>
        public static void LogServiceStartingInformation()
        {
            Logger.WriteOperationalInformation(0x0A /* eventId*/, LogStrings.ServiceStartingInformation);
        }

        /// <summary>
        /// Log an informational message to the event log that the service started.
        /// </summary>
        /// <remarks>
        /// This method is invoked when one of the Enhanced Reminders services completes starting successfully.
        /// </remarks>
        public static void LogServiceStartedInformation()
        {
            Logger.WriteOperationalInformation(0x0B /* eventId*/, LogStrings.ServiceStartedInformation);
        }

        /// <summary>
        /// Log an informational message to the event log that service is stopping.
        /// </summary>
        /// <remarks>
        /// This method is invoked when one of the Enhanced Reminders services begins to stop.
        /// </remarks>
        public static void LogServiceStoppingInformation()
        {
            Logger.WriteOperationalInformation(0x0C /* eventId*/, LogStrings.ServiceStoppingInformation);
        }

        /// <summary>
        /// Log an informational message to the event log that the service stopped.
        /// </summary>
        /// <remarks>
        /// This method is invoked when one of the Enhanced Reminders services stops.
        /// </remarks>
        public static void LogServiceStoppedInformation()
        {
            Logger.WriteOperationalInformation(0x0D /* eventId*/, LogStrings.ServiceStoppedInformation);
        }

        /// <summary>
        /// Logs a warning message to the event log that the service took longer than expected to shut down.
        /// </summary>
        /// <param name="timeout">The service shutdown timeout</param>
        /// <remarks>
        /// This method is invoked when the service takes longer than the shutdown timeout to stop. This is mostly caused by the timeout 
        /// being too short or because a notification is taking too long. The consequence of this warninig is that the service might not 
        /// shut down cleanly. For example, a notification might not complete.
        /// </remarks>
        public static void LogServiceShutdownTimeoutWarning(int timeout)
        {
            Logger.WriteOperationalWarning(0x0E /* eventId*/, LogStrings.ServiceShutdownTimeoutWarning, timeout);
        }

        /// <summary>
        /// Logs an error message to the event log that the service experienced a fatal error at start-up.
        /// </summary>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when there is an error during service start-up. This could be because of external errors or because 
        /// of a misconfiguration. The admin should consult the event log for additional error logs. The consequence of this error is 
        /// that the service won't start and users won't receive notifications.
        /// </remarks>
        public static void LogServiceStartError(Exception ex)
        {
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x0F /* eventId*/, ex, LogStrings.ServiceStartError);
        }

        /// <summary>
        /// Logs an error message to the event log that the specified scratch directory could not be created.
        /// </summary>
        /// <param name="scratchDirectoryPath">The path of the scratch directory</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when there is an error creating the scratch directory. The most likely cause is that the service
        /// does not have permission to create the directory or the disk is full. The consequence of this error is that the affected 
        /// service won't start and users won't receive notifications.
        /// </remarks>
        public static void LogScratchDirectoryCreateError(string scratchDirectoryPath, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(scratchDirectoryPath), "!String.IsNullOrEmpty(scratchDirectoryPath)");
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x10 /* eventId*/, ex, LogStrings.ScratchDirectoryCreateError, scratchDirectoryPath);
        }

        /// <summary>
        /// Logs a warning message to the event log that the specified scratch directory could not be cleaned up at shutdown.
        /// </summary>
        /// <param name="scratchDirectoryPath">The path of the scratch directory</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when the scratch directory cannot be deleted. This is most likely because the directory does not exist 
        /// or the service does not have permission to delete the directory. The consequence of this warning is that voicemail audio files 
        /// containing sensitive information may be left on this machine.
        /// </remarks>
        public static void LogScratchDirectoryCleanupWarning(string scratchDirectoryPath, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(scratchDirectoryPath), "!String.IsNullOrEmpty(scratchDirectoryPath)");
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalWarning(0x11 /* eventId*/, ex, LogStrings.ScratchDirectoryCleanupWarning, scratchDirectoryPath);
        }

        /// <summary>
        /// Logs an error message to the event log that no SIP address could be found for the specified user.
        /// </summary>
        /// <param name="user">The user account experiencing the error</param>
        /// <remarks>
        /// This method is invoked when a SIP address cannot be found for the specified user. The most likely cause is that the user is not 
        /// in Active Directory or Active Directory is not working correctly. It could also be that the user is not registered with OCS. The
        /// consequence of this error is that this user will not receive any notifications.
        /// </remarks>
        public static void LogNoSipAddressError(string user)
        {
            Debug.Assert(!String.IsNullOrEmpty(user), "!String.IsNullOrEmpty(user)");

            Logger.WriteOperationalError(0x12 /* eventId*/, LogStrings.NoSipAddressError, user);
        }

        /// <summary>
        /// Logs an error message to the event log that an outbound voice notification to the specified user failed.
        /// </summary>
        /// <param name="user">The user account experiencing the error</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when a voice call for the specified user fails. The most likely cause is an external issue with OCS.
        /// The consequence of this error is that the user won't receive voice notifications.
        /// </remarks>
        public static void LogVoiceNotificationError(string user, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(user), "!String.IsNullOrEmpty(user)");
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x13 /* eventId*/, ex, LogStrings.VoiceNotificationError, user);
        }

        /// <summary>
        /// Logs an error message to the event log that an SMS notification to the specified user failed.
        /// </summary>
        /// <param name="user">The recipient of the SMS</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when an SMS notification for the specified recipient fails. This is most likely an external issue
        /// with SMTP. The consequence of this error is that the user will not receive SMS notifications.
        /// </remarks>
        public static void LogSmsNotificationError(string user, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(user), "!String.IsNullOrEmpty(user)");
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x14 /* eventId*/, ex, LogStrings.SmsNotificationError, user);
        }

        /// <summary>
        /// Logs an error message to the event log that an IM notification to the specified user failed.
        /// </summary>
        /// <param name="user">The user account experiencing the error</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when an IM notification for the specified user fails. This is most likely caused by an external issue 
        /// with OCS. The consequence of the error is that this user won't receive IM notifications.
        /// </remarks>
        public static void LogInstantMessageNotificationError(string user, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(user), "!String.IsNullOrEmpty(user)");
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x15 /* eventId*/, ex, LogStrings.InstantMessageNotificationError, user);
        }

        /// <summary>
        /// Logs an error message to the event log that a notification could not be delivered to the Dispatcher service.
        /// </summary>
        /// <param name="reason">Reason code associated with the error</param>
        /// <param name="queueName">The name of the message queue associated with the error</param>
        /// <remarks>
        /// This method is invoked when the Scheduler is unable to deliver notification requests to the Dispatcher. The most likely cause 
        /// is that the Dispatcher is not operating correctly. The consequence of this error is that users won't receive notifications.
        /// </remarks>
        public static void LogNotificationDeliveryError(string reason, string queueName)
        {
            Debug.Assert(!String.IsNullOrEmpty(reason), "!String.IsNullOrEmpty(reason)");
            Debug.Assert(!String.IsNullOrEmpty(queueName), "!String.IsNullOrEmpty(queueName)");

            Logger.WriteOperationalError(0x16 /* eventId*/, LogStrings.NotificationDeliveryError, reason, queueName);
        }

        /// <summary>
        /// Logs an error message to the event log that the specified SIP server could not be reached.
        /// </summary>
        /// <param name="address">Address of the SIP server</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when the configured SIP server cannot be reached. The most likely cause is that the address of the server 
        /// is misconfigured or the machine is unreachable. The consequence of this error is that the service won't start and users won't 
        /// receive notifications.
        /// </remarks>
        public static void LogSipUnreachableError(string address, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(address), "!String.IsNullOrEmpty(address)");
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x17 /* eventId*/, ex, LogStrings.SipUnreachableError, address);
        }

        /// <summary>
        /// Logs an error message to the event log that registration with the specified SIP server failed.
        /// </summary>
        /// <param name="address">Address of the SIP server</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when registration with the configured SIP server fails. The most likely cause is the service account
        /// is not registered with OCS. The consequence of this error is that the service won't start and users won't receive 
        /// notifications.
        /// </remarks>
        public static void LogSipRegistrationError(string address, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(address), "!String.IsNullOrEmpty(address)");
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x18 /* eventId*/, ex, LogStrings.SipRegistrationError, address);
        }

        /// <summary>
        /// Logs an error message to the event log that writing to the specified scratch directory failed.
        /// </summary>
        /// <param name="scratchDirectoryPath">The path of the scratch directory</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when there is an error writing to the scratch directory. The most likely cause is that the directory does 
        /// not exist or the service does not have permission to write to this directory or the disk is full. The consequence of this error 
        /// is that voicemail notifications will fail.
        /// </remarks>
        public static void LogScratchDirectoryWriteError(string scratchDirectoryPath, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(scratchDirectoryPath), "!String.IsNullOrEmpty(scratchDirectoryPath)");
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x19 /* eventId*/, ex, LogStrings.ScratchDirectoryWriteError, scratchDirectoryPath);
        }

        /// <summary>
        /// Logs a warning message to the event log that the specified file could not be deleted from the scratch directory.
        /// </summary>
        /// <param name="scratchDirectoryFile">The path of the file in the scratch directory</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when the specified file cannot be deleted. The most likely cause is that the file does not exist or 
        /// the service does not have permission to delete the file. The consequence of this warning is that a voicemail audio file may 
        /// be left on the machine containing sensitive information.
        /// </remarks>
        public static void LogScratchDirectoryDeleteWarning(string scratchDirectoryFile, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(scratchDirectoryFile), "!String.IsNullOrEmpty(scratchDirectoryFile)");
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalWarning(0x1A /* eventId*/, ex, LogStrings.ScratchDirectoryDeleteWarning, scratchDirectoryFile);
        }

        /// <summary>
        /// Logs an error message to the event log that the AD query for users failed.
        /// </summary>
        /// <param name="activeDirectoryRoot">Value of the AD configuration setting</param>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when the AD query for users fails. The most likely cause is that the configured LDAP root 
        /// is incorrect. The consequence of this type of error is that the service won't start and users won't receive 
        /// notifications.
        /// </remarks>
        public static void LogActiveDirectorySearchError(string activeDirectoryRoot, Exception ex)
        {
            Debug.Assert(!String.IsNullOrEmpty(activeDirectoryRoot), "!String.IsNullOrEmpty(activeDirectoryRoot)");
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x1B /* eventId*/, ex, LogStrings.ActiveDirectorySearchError, activeDirectoryRoot);
        }

        /// <summary>
        /// Logs a warning message to the event log that the connection to OCS was lost.
        /// </summary>
        /// <remarks>
        /// This is invoked when the state of the OCS endpoint used by the Dispatcher service terminates prematurely.
        /// This is just a warning message, as the service should automatically attempt to reconnect.
        /// </remarks>
        public static void LogOcsConnectionWarning()
        {
            Logger.WriteOperationalWarning(0x1C /* eventId */, LogStrings.LostOcsConnectionWarning);
        }

        /// <summary>
        /// Logs an informational message to the event log that the service has connected to OCS.
        /// </summary>
        /// <remarks>
        /// This is called when the Dispatcher service connects to OCS.
        /// </remarks>
        public static void LogReconnectedToOcs()
        {
            Logger.WriteOperationalInformation(0x1D /* eventId */, LogStrings.ReconnectedToOcs);
        }

        /// <summary>
        /// Logs an error message to the event log that we could not load the WM encoder dlls.
        /// </summary>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when there is an error encoding voicemail audio to wav.
        /// </remarks>
        public static void LogWindowsMediaEncoderNotFoundError(Exception ex)
        {
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x1E /* eventId*/, ex, LogStrings.WMEncoderError);
        }

        /// <summary>
        /// Logs an error message to the event log that we could not load the WM encoder dlls.
        /// </summary>
        /// <param name="ex">The error associated with this log message</param>
        /// <remarks>
        /// This method is invoked when there is an error encoding voicemail audio to wav.
        /// </remarks>
        public static void LogWindowsMediaEncoderFailedError(Exception ex)
        {
            Debug.Assert(ex != null, "ex != null");

            Logger.WriteOperationalError(0x1F /* eventId*/, ex, LogStrings.WMEncoderPatchError);
        }

        /// <summary>
        /// Logs an error message to the event log that no notifications are arriving from Exchange.
        /// </summary>
        /// <remarks>
        /// This method is invoked when no notifications from Exchange have been received within the timeout period. The most 
        /// likely cause is that either the configured notification URL is unreachable or Exchange is not operating correctly.
        /// The consequence of this type of error is that changes to users' mailboxes will not be detected.
        /// </remarks>
        public static void LogNoNotificationsError(string notificationSettingName)
        {
            Debug.Assert(!String.IsNullOrEmpty(notificationSettingName), "!String.IsNullOrEmpty(notificationSettingName)");

            Logger.WriteOperationalError(0x20 /* eventId*/, LogStrings.NoNotificationsError, notificationSettingName);
        }

        /// <summary>
        /// Logs an informational message to the event log that notifications are arriving from Exchange.
        /// </summary>
        /// <remarks>
        /// This method is invoked the first time a notifications from Exchange is received following a notification timeout. This
        /// informs the admin that the connection with Exchange has been re-established.
        /// </remarks>
        public static void LogConnectionEstablishedInformation()
        {
            Logger.WriteOperationalInformation(0x21 /* eventId*/, LogStrings.ConnectionEstablishedInformation);
        }

        /// <summary>
        /// Logs an error message to the event log that the certificate for registering with OCS could not be found.
        /// </summary>
        public static void LogCertificateNotFoundError()
        {
            Logger.WriteOperationalError(0x22 /* eventId*/, LogStrings.CertificateNotFoundError);
        }
    }
}
